#include "pch.hpp"
#include "Builder.hpp"

using namespace Engine;
using namespace Engine::Script;
namespace fs = boost::filesystem;
namespace io = boost::iostreams;




Builder::Builder(logger::stream::ptr logger, pointer<asIScriptEngine> engine)
	: m_logger(logger)
	, m_engine(engine)
	, m_module(nullptr)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

Builder::Builder(const Builder& that)
	: m_logger(that.m_logger)
	, m_engine(that.m_engine)
	, m_module(nullptr)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

Builder::~Builder()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




Builder& Builder::operator=(const Builder& that)
{
	m_logger = that.m_logger;
	m_engine = that.m_engine;
	m_module = nullptr;

	return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Builder::start(QString name)
{
	if(m_module)
	{
		m_engine->DiscardModule(m_module->GetName());
		m_module = nullptr;
	}

	auto data = name.toUtf8();
	auto module = m_engine->GetModule(data.constData(), asGM_ALWAYS_CREATE);
	verify(module != nullptr);
	m_module = module;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Builder::add(QString name, QTextStream& stream)
{
	QString code = preprocess(stream);
	addSection(name, code);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Builder::add(QString name, QString code)
{
	QByteArray data = code.toUtf8();
	QTextStream stream(&code);
	add(name, stream);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Builder::add(QString name, const boost::filesystem::path& path)
{
	verify(fs::exists(path));
	verify(fs::is_regular_file(path));

	auto ext = path.extension();
	verify(ext == ".as");

	QFile file(path.string().c_str());
	verify(file.open(QIODevice::ReadOnly));
	QTextStream stream(&file);

	add(name, stream);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Module::ptr Builder::build()
{
	auto handle = m_module;
	m_module = nullptr;

	if(handle->Build() < 0)
		return Module::ptr();
	else
		return boost::make_shared<Module>(handle);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

QString Builder::preprocess(QTextStream& stream) const
{
	QString code, line;
	bool comment = false;

	while(!stream.atEnd())
	{
		line = stream.readLine();

		// Preprocessing part:
		// Single line comments
		auto i = line.indexOf("//");
		if(i != -1)
		{
			line = line.left(i);
		}

		// Multiline comment
		if(!comment)
		{
			i = line.indexOf("/*");
			if(i != -1)
			{
				line = line.left(i);
				comment = true;
			}
		}
		else
		{
			i = line.indexOf("*/");
			if(i != -1)
			{
				line = line.right(line.size() - i);
				comment = false;
			}
			else
			{
				line.clear();
			}
		}

		if(code.size() > 0)
			code += '\n';
		code += line;
	}

	return code;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Builder::addSection(QString name, QString code)
{
	verify(m_module != nullptr);

	QByteArray nameData = name.toUtf8();
	QByteArray codeData = code.toUtf8();

	verify(m_module->AddScriptSection(nameData.constData(), codeData.constData(), codeData.size()) >= 0);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
